import requests
import time
import random
import threading
import json
lock = threading.Lock()

links ={
     "host" : "http://www.xpub.com",
    # 请求接口池
    "urls" : [
       '/api/app/app_download_url?',
        '/api/message/message_count?',
        '/api/user/user?',
        '/api/market/market_currency_rate?',
        '/api/message/message_count?',
        '/api/market/market_rate?',
        '/api/account/account_asset_bch?',
    ],
    "headers":{
       "Cookie":"",
       "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.33 Safari/537.36"
    }
}

conf={
    "MAXL" : 10,       # 每个线程请求多少次
    "MAXT" : 100       # 并发线程数
}

# 统计
stat = {
    "total" : 0,      # 总请求数
    "totaltime" :0,   # 总时间
    "succ" : 0,       # 成功数
    "succRatio": 0,   # 成功率
    "fail" : 0,       # 失败数
    "except": 0,      # 异常数
    "maxtime" : 0,    # 最大响应时间
    "mintime" : 100,  # 最小响应时间
    "sta"     : 500, # 快慢标准 ms
    "slow"    : 0,    # 慢
    "slowRatio": 100, # 慢比率
}

# 请求一次接口
def linkAPI(stat,reqUrl,reqData) :
    try :
        st = time.time()  # 开始时间
        r = requests.get(reqUrl) # 请求链接
        timeD = time.time() - st  # 结束时间 - 开始时间

        lock.acquire(1) # 同步锁
        if r.status_code == 200:
            print('%d[200]%s ---> %.2f ms'%(stat['total'],reqUrl,timeD*1000))
            stat["succ"] += 1
            stat["total"] += 1
        else :
            print('%d[%d]%s ---> %.2f ms'%(stat['total'],r.status_code,reqUrl,timeD*1000))
            stat["total"] += 1
            stat["fail"] += 1
        # 统计最长最短时间
        if timeD < stat["mintime"] : stat['mintime'] = timeD 
        if timeD > stat["maxtime"] : stat["maxtime"] = timeD
        # 统计慢响应数量
        if timeD*1000 > stat["sta"] : stat["slow"] += 1
        stat["totaltime"] += timeD
        lock.release()
    except Exception as e:
        print(e)
        lock.acquire(1) # 同步锁
        try:
            stat["tolal"] += 1
            stat["except"] += 1
            lock.release()
        except Exception :
            lock.release()
    finally:
        r.close()
# 计算
def statCalc(stat):
    # 计算成功率
    stat['succRatio'] = stat['succ']/stat['total']*100
    # 慢链接率
    stat['slowRatio'] = stat["slow"]/stat["total"]*100
    # 平均时间
    stat['aveTime']   = stat["totaltime"]/stat["total"]

# 打印与记录
def resPrint(stat,MAXT):
    lines = []
    lines.append("\n"+time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
    lines.append('==================================')
    lines.append("总量: %d | 成功: %d | 失败: %d |异常: %d | 成功率 %.2f"%(stat['total'], stat["succ"], stat["fail"], stat['except'],stat['succRatio'])+"%")
    lines.append("最小时间: %.2fms | 最大时间: %.2fms "%(stat['mintime']*1000, stat["maxtime"]*1000))
    lines.append("慢连接数量(>%dms): %d | 慢链接占比:%.3f"%(stat['sta'], stat["slow"], stat['slowRatio'])+"%")
    lines.append("总时间： %.2fs |平均时间：%.2fms"%(stat["totaltime"], stat['aveTime']*1000))
    lines.append('线程数:%d'%MAXT)
    # 写日志
    with open('./pressure.py.log','a') as fp:
        # wStr = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        stat["time"] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        stat['MAXT'] = MAXT
        wStr = json.dumps(stat, sort_keys=True, indent=4)
        fp.write(wStr+'\n')
    # 写结果
    with open('./pressure.py.txt','a',encoding="utf-8") as fp:
        wStr = ''
        for one in lines: wStr += one+'\n'
        fp.write(wStr)
    # 显示
    for one in lines: print(one)
        
# 随机获取一个链接
def getRandomLink(links):
    return links['host'] + links["urls"][random.randint(0,len(links["urls"])-1)]+ str(random.randint(0,500))

# 单个线程的任务
def oneThread(MAX,stat,links):
    for x in range(0,MAX): linkAPI(stat,getRandomLink(links),[])


if __name__ == '__main__':
    threads = []       # 线程池
    for x in range(0,conf["MAXT"]):
        try:
            t = threading.Thread(target=oneThread,args=(conf["MAXL"],stat,links))
            threads.append(t)
            t.start()
        except Exception as e:
            pass
    # 等待进程完结
    for t in threads : t.join()
    # 计算
    statCalc(stat)
    # 显示
    resPrint(stat,conf["MAXT"])
    